/**
 *    @file       httptoolkit.cpp
 *
 *    @brief      
 *    @details
 *
 *    @version    1.0
 *    @date       01/16/2014 11:47:46 PM
 *
 *    @author     Theophilus (), wangtf418@gmail.com 
 */
#include "httptoolkit.h"
#include "toolkit.h"

httptoolkit::httptoolkit()
{

}

httptoolkit::~httptoolkit()
{

}

//=====================================================
void httptoolkit::url_encode(const std::string &str, std::string &str_out)
{
	str_out.clear();
	str_out.reserve(str.length() * 3);
	bf_size_t strlen = str.length();
	bf_char_t buf[4];
	for (bf_size_t i = 0; i < strlen; i ++)
	{
		if (str[i] == ' ')
		{
			str_out.append(1, '+');
		}
		else if (BF_URL_ENCODE_MAP[(bf_uint8_t)str[i]])
		{
			snprintf(buf, sizeof(buf), "%c%02X", '%', (bf_uint8_t)str[i]);
			str_out.append(buf);
		}
		else
		{
			str_out.append(1, str[i]);
		}
	}
}

void httptoolkit::url_decode(const std::string &str, std::string &str_out)
{
	str_out.clear();
	str_out.reserve(str.length());

	bf_uint64_t num;
	bf_size_t strlen = str.length();
	bf_size_t curpos = 0;
	while (curpos < strlen)
	{
		if (str[curpos] == '+')
		{
			str_out.append(1, ' ');
			curpos ++;
		}
		else if (str[curpos] == '%')
		{
			if (strlen - curpos > 2 && toolkit::hex2int(str.c_str() + curpos + 1, 2, num) == BF_OK)
			{
				str_out.append(1, (std::string::value_type)num);
				curpos += 3;
			}
			else
			{
				str_out.append(1, str[curpos]);
				curpos ++;
			}
		}
		else
		{
			str_out.append(1, str[curpos]);
			curpos ++;
		}
	}
}

bf_int_t httptoolkit::proc_http_header(const bf_char_t *head, bf_size_t headlen, http_reqfirstline_t &firstline, http_headfields_t &headfields)
{
	std::vector<bf_string_t> lines;
	bf_int_t ret = toolkit::split_string_by_string(head, headlen, "\r\n", lines);
	if (ret != BF_OK || lines.size() == 0)
	{
		return BF_ERROR;
	}
	std::vector<bf_string_t> split;
	ret = toolkit::split_string_by_chars(lines[0].m_str, lines[0].m_len, " ", split);
	if (ret != BF_OK || split.size() != 3)
	{
		return BF_ERROR;
	}
	firstline.m_method = split[0].to_string();
	firstline.m_path = split[1].to_string();
	firstline.m_version = split[2].to_string();
	
	headfields.m_reqheaders.clear();
	bf_size_t linenum = lines.size();
	std::string fieldname;
	for (bf_size_t i = 1; i < linenum; i ++)
	{
		ret = toolkit::split_string_by_string(lines[i].m_str, lines[i].m_len, ":", split);
		if (ret != BF_OK || split.size() != 2)
		{
			return BF_ERROR;
		}
		toolkit::trim_string(split[0], " ");
		toolkit::trim_string(split[1], " ");
		fieldname = split[0].to_string();
		toolkit::str_upper2lower((bf_char_t*)fieldname.c_str(), fieldname.length());
		headfields.m_reqheaders[fieldname] = http_field_t(split[0].to_string(), split[1].to_string());
	}
	return BF_OK;
}

std::string httptoolkit::gen_http_header(const http_reqfirstline_t &firstline, const http_headfields_t &headfields)
{
	std::string head;
	head.reserve(1024);
   	head = firstline.m_method + " " + firstline.m_path + " " + firstline.m_version + "\r\n";
	std::map<std::string, http_field_t>::const_iterator itr = headfields.m_reqheaders.begin();
	while (itr != headfields.m_reqheaders.end())
	{
		head += itr->second.m_name + ": " + itr->second.m_value + "\r\n";
		itr ++;
	}
	head += "\r\n";
	return head;
}

